home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Human Interface Toolbox / Live Control Scroll / Live Controls Scroll.c < prev   
Encoding:
Text File  |  2000-09-28  |  23.9 KB  |  753 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        Scroll Controls Offscreen.c
  3.  
  4.     Contains:    Sample code illustrating scrolling of controls via an off screen GWorld
  5.  
  6.     Written by:    Geoff Stahl (ggs)
  7.  
  8.     Copyright:    Copyright (c) 1999 Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.                 
  18. */
  19.  
  20. // system includes ----------------------------------------------------------
  21.  
  22. #include <MacMemory.h>
  23. #include <Events.h>
  24. #include <Fonts.h>
  25. #include <Windows.h>
  26. #include <TextEdit.h>
  27. #include <Dialogs.h>
  28. #include <Sound.h>
  29. #include <SoundInput.h>
  30. #include <ToolUtils.h>
  31. #include <OSUtils.h>
  32. #include <Controls.h>
  33. #include <Devices.h>
  34. #include <LowMem.h>
  35.  
  36. #include <stdlib.h>
  37.  
  38.  
  39. // project includes ---------------------------------------------------------
  40.  
  41.  
  42.  
  43. // statics/globals (internal only) ------------------------------------------
  44.  
  45. // Menu defs
  46. enum 
  47. {
  48.     kMenuApple = 128,
  49.     kMenuFile = 129,
  50.     
  51.     kFileQuit = 1,
  52.     
  53.     kButtonMenuID = 150
  54. };
  55.  
  56. enum
  57. {
  58.                                                     // Window Constants
  59.     kOffScreenHeight = 1600,                        // self e.
  60.     kOffScreenWidth = 900,                            //   "
  61.     kWindowHeight = 400,                            //   "
  62.     kWindowWidth = 500,                                //   "
  63.     kWindowOffset = 100,                            //   "
  64.     
  65.                                                     // Scroll bar constants
  66.     kScrollBarWidth = 16,                            // fixed
  67.     kScrollArrowWidth = kScrollBarWidth,            //   "
  68.     kScrollBarWidthAdjust = kScrollBarWidth - 1,    //   "
  69.     
  70.     kPageOverlap = 10,                        // overlap for a page down or up
  71.     kThumbTrackSlop = 100,                    // delta from scroll bar for snap to start
  72.     
  73.     kNumControls = 400                        // number of controls
  74. };
  75.  
  76. Rect gRectWindowGbl;                        // window rectanglein global coordinates
  77.  
  78. ControlHandle ghControls [kNumControls];    // test controls
  79. Point gPtCntlPos [kNumControls];            // initial control postions
  80.  
  81. WindowPtr gpWindow = NULL;                    // main window
  82. GWorldPtr gpGWOffScreen = NULL;                // main window offscreen scratch
  83.  
  84. short gScrollVThumbSize = 0;
  85. short gScrollHThumbSize = 0;
  86. short gTotalVSizeAdjust = 0;
  87. short gTotalHSizeAdjust = 0;
  88.  
  89. ControlHandle ghHScrollBar = NULL;            // main window scroll bar
  90. ControlHandle ghVScrollBar = NULL;            // main window scroll bar
  91.  
  92. RgnHandle gSaveClip = NULL;                    // clipping save for control drawing exclusions
  93. ControlRef gControl;                        // active scroll control
  94. SInt32 gStartValue;                            // scroll start value
  95. SInt32 gValueSlop;                            // slop for mouse live scroll calcs
  96. SInt32 gSaveValue;                            // current scroll value on live exit
  97.  
  98. SInt32 gSleepTime = 60;                        // WaitNextEvent sleep time
  99. Boolean gDone = false;                        // done yet
  100.  
  101. // functions Prototypes (internal/private) -----------------------------------
  102.  
  103. void CleanUp (void);                                                    // clean ups after application
  104. void ScrollControls (WindowPtr pWinParent, short left, short top);        // moves postion of controls in relation to scrolled positon of window without updating
  105. void ScrollDrawContent (WindowPtr pWindow, short wWindowLeft, short wWindowTop); // draws contents from offscreen to on and diretcly draws scroll bar on screen
  106. void DoUpdate (WindowPtr pWindow);                                        // draw from off screen to on and updates control postions on screen for events
  107. void MoveScroll (ControlHandle hScrollBar, short wDist);                // adjust scroll bar cotnrol position accouting for control limits
  108. pascal void ProcScroll (ControlHandle hControl, short wPart);            // proc to handle clicks in scroll bar gray or arrows (page up/down, line up/down)
  109. void EndThumbTracking (void);                                            // handles release of live scroll
  110. SInt32 CalcValueFromPoint (ControlHandle hControl, Point thePoint);        // converts mouse to scroll postion and handles out of slop area
  111. pascal void ProcScrollThumbAction (void);                                // proc to handle live scrolling
  112. OSErr BeginThumbTracking (ControlRef hControl);                            // handles beginning of live scrolling
  113. void DrawOneControlOffscreen (ControlHandle hControl);                    // updates the image of hControl for offscreen
  114. void DoContentClick (WindowPtr pWindow, EventRecord * pEvent);            // overall content click handler
  115. void DoMenu (SInt32 menuResult);                                        // menu event handler
  116. void DoEvent (void);                                                    // event handler
  117. void DrawOffScreen (CGrafPtr pCGOffScreen);                                // offscreen update (this would also be called for control value updates)
  118. void SetScrollParams (WindowPtr hWindow);                                // sets scroll bar size reference vars
  119. void AdjustScrollBar (WindowPtr pWindow, ControlHandle scrollBar);        // sets appearance savvy portional scroll bar up
  120. void InitToolbox(void);                                                    // standard inits
  121. Boolean SetUp (void);                                                    // application setup
  122.  
  123. // NOTE: Initial control position is stored in gPtCntlPos Point array to allow reference during scrolling, 
  124.  
  125. // functions (internal/private) ---------------------------------------------
  126.  
  127. void CleanUp (void)
  128. {
  129.     MenuHandle hMenu;
  130.  
  131.     HideWindow (gpWindow);
  132.     KillControls (gpWindow);
  133.     if (gpWindow)
  134.         DisposeWindow (gpWindow);
  135.     gpWindow = NULL;
  136.     if (gpGWOffScreen)
  137.         DisposeGWorld (gpGWOffScreen);
  138.     gpGWOffScreen = NULL;
  139.     
  140.     hMenu = GetMenu (kButtonMenuID);
  141.     DeleteMenu (kButtonMenuID);
  142.     DisposeMenu (hMenu);
  143.  
  144.     hMenu = GetMenu (kButtonMenuID);
  145.     DeleteMenu (kMenuFile);
  146.     DisposeMenu (hMenu);
  147.  
  148.     hMenu = GetMenu (kButtonMenuID);
  149.     DeleteMenu (kMenuApple);
  150.     DisposeMenu (hMenu);
  151. }
  152.  
  153. // --------------------------------------------------------------------------
  154.  
  155. void ScrollControls (WindowPtr pWinParent, short left, short top)
  156. {
  157.      Rect rectNull = {0, 0, 0, 0};
  158.     GrafPtr pGrafSave;
  159.     RgnHandle hRgnClipSave;
  160.     short i;
  161.     
  162.     GetPort (&pGrafSave);
  163.     SetPort ((GrafPtr) pWinParent);
  164.     
  165.     // set the clip region to empty to avoid updates
  166.     hRgnClipSave = NewRgn ();
  167.     GetClip ( hRgnClipSave );
  168.     ClipRect ( &rectNull );
  169.     
  170.     // move controls to support mouse down events in the window
  171.     for (i = 0; i < kNumControls; i++)
  172.         if (((gPtCntlPos [i].v - top) != (**ghControls[i]).contrlRect.top) || ((gPtCntlPos [i].h - left) != (**ghControls[i]).contrlRect.left))// move Controls for window pos using top stored in refcon
  173.             MoveControl (ghControls[i], gPtCntlPos [i].h - left, gPtCntlPos [i].v - top);
  174.  
  175.     SetClip (hRgnClipSave);
  176.     SetPort (pGrafSave);
  177. }
  178.  
  179. // --------------------------------------------------------------------------
  180.  
  181. void ScrollDrawContent (WindowPtr pWindow, short wWindowLeft, short wWindowTop)    // offset and draw window content from offscreen to on
  182. {
  183.     Rect rectDest = ((GrafPtr)pWindow)->portRect;
  184.     Rect rectSource = ((GrafPtr)pWindow)->portRect;
  185.     
  186.     GrafPtr pCGrafSave;
  187.     GetPort (&pCGrafSave);
  188.  
  189.     SetPort ((GrafPtr) pWindow);
  190.     
  191.     OffsetRect (&rectSource, wWindowLeft, wWindowTop);    // offset for position in offscreen
  192.  
  193.     rectDest.right -= kScrollBarWidthAdjust;            // don't draw scroll bars
  194.     rectDest.bottom -= kScrollBarWidthAdjust;
  195.  
  196.     rectSource.right -= kScrollBarWidthAdjust;
  197.     rectSource.bottom -= kScrollBarWidthAdjust;
  198.     
  199.     CopyBits (&((GrafPtr)gpGWOffScreen)->portBits, &pWindow->portBits, &rectSource, &rectDest, srcCopy, NULL);
  200.     
  201.     Draw1Control (ghHScrollBar); // draw scroll bar
  202.     Draw1Control (ghVScrollBar); // draw scroll bar
  203.     
  204.     SetPort (pCGrafSave);
  205. }
  206.  
  207. // --------------------------------------------------------------------------
  208.  
  209. void DoUpdate (WindowPtr pWindow)
  210. {
  211.     ScrollDrawContent (pWindow, GetControlValue (ghHScrollBar), GetControlValue (ghVScrollBar));    // draw content offscreen to on 
  212.     ScrollControls (pWindow, GetControlValue (ghHScrollBar), GetControlValue (ghVScrollBar));         // update controls positions
  213. }
  214.  
  215. // --------------------------------------------------------------------------
  216.  
  217. void MoveScroll (ControlHandle hScrollBar, short wDist)    // update thumb position check for ends
  218. {
  219.     short wScrollPos = GetControlValue (hScrollBar);            
  220.     wScrollPos = wScrollPos + wDist;
  221.  
  222.     if ( wScrollPos < GetControlMinimum ( hScrollBar ) )
  223.         wScrollPos = GetControlMinimum ( hScrollBar );
  224.     else if ( wScrollPos > GetControlMaximum ( hScrollBar ) )
  225.         wScrollPos = GetControlMaximum ( hScrollBar );
  226.  
  227.     SetControlValue (hScrollBar, wScrollPos);
  228. }
  229.  
  230. // --------------------------------------------------------------------------
  231.  
  232. pascal void ProcScroll (ControlHandle hControl, short wPart)    // handle scroll callback
  233. {
  234.     WindowPtr pWindow = (**hControl).contrlOwner;
  235.     short wScrollDist = 0;
  236.     switch (wPart)
  237.     {
  238.         case kControlIndicatorPart:            // scroll up
  239.             wScrollDist = gStartValue - GetControlValue (hControl); 
  240.             break;
  241.         case kControlUpButtonPart:            // scroll up
  242.             wScrollDist = -2;
  243.             break;
  244.         case kControlDownButtonPart:        // scroll down
  245.             wScrollDist = 2;
  246.             break;
  247.         case kControlPageUpPart:            // page up
  248.             if ( hControl == ghHScrollBar)
  249.                 wScrollDist = -(pWindow->portRect.right - pWindow->portRect.left - kPageOverlap);
  250.             else
  251.                 wScrollDist = -(pWindow->portRect.bottom - pWindow->portRect.top - kPageOverlap);
  252.             break;
  253.         case kControlPageDownPart:            // page up
  254.             if ( hControl == ghHScrollBar)
  255.                 wScrollDist = (pWindow->portRect.right - pWindow->portRect.left - kPageOverlap);
  256.             else
  257.                 wScrollDist = (pWindow->portRect.bottom - pWindow->portRect.top - kPageOverlap);
  258.             break;
  259.     }
  260.     if ((wScrollDist) && (pWindow))
  261.     {
  262.         MoveScroll (hControl, wScrollDist);
  263.         ScrollDrawContent (pWindow, GetControlValue (ghHScrollBar), GetControlValue (ghVScrollBar));
  264.     }
  265. }
  266.  
  267. // --------------------------------------------------------------------------
  268.  
  269. void EndThumbTracking ( void )    // mouse up on thumb determine and set final value
  270. {
  271.     SetClip (gSaveClip);
  272.     DisposeRgn (gSaveClip);
  273.     SetControlValue (gControl, gSaveValue);    
  274.     gSaveValue = 0;    
  275.     return;
  276. }
  277.  
  278. // --------------------------------------------------------------------------
  279.  
  280. SInt32 CalcValueFromPoint (ControlHandle hControl, Point thePoint)    // figure where we are in scroll bar terms
  281. {
  282.     SInt32 theValue = 0, theRange, theDistance, thePin;
  283.     Rect rectControl;
  284.     WindowPtr pWindow;
  285.     
  286.     pWindow = (*hControl)->contrlOwner;
  287.         
  288.     rectControl = (*hControl)->contrlRect;
  289.     theRange = GetControlMaximum ( hControl ) - GetControlMinimum ( hControl );
  290.     if ( hControl == ghHScrollBar)
  291.     {
  292.         // Scroll distance adjusted for scroll arrows and the thumb
  293.         theDistance = rectControl.right - rectControl.left - gTotalHSizeAdjust;
  294.         // Pin thePoint to the middle of the thumb
  295.         thePin = rectControl.left + (gScrollHThumbSize / 2);
  296.         theValue = ((thePoint.h - thePin) * theRange) / theDistance;
  297.     }
  298.     else if ( hControl == ghVScrollBar)
  299.     {
  300.         // Scroll distance adjusted for scroll arrows and the thumb
  301.         theDistance = rectControl.bottom - rectControl.top - gTotalVSizeAdjust;
  302.         // Pin thePoint to the middle of the thumb
  303.         thePin = rectControl.top + (gScrollVThumbSize / 2);
  304.         theValue = ((thePoint.v - thePin) * theRange) / theDistance;
  305.     }
  306.     theValue += gValueSlop;
  307.     return theValue;
  308. }
  309.  
  310. // --------------------------------------------------------------------------
  311.  
  312. pascal void ProcScrollThumbAction (void)    // handle thumb callbacks
  313. {
  314.     Rect            rectNull = {0, 0, 0, 0};
  315.     SInt32            theValue;
  316.     WindowRef        pWindow;
  317.     ControlRef        hControl = gControl;
  318.     Point            thePoint;
  319.     Rect            rectControl;
  320.     
  321.     
  322.     pWindow = (*hControl)->contrlOwner;
  323.     
  324.      rectControl = (*hControl)->contrlRect;
  325.      InsetRect (&rectControl, -kThumbTrackSlop, -kThumbTrackSlop);    // expand control rect by tracking slop
  326.     
  327.     // Assumes the port is correctly set up
  328.     GetMouse (&thePoint);
  329.     if (PtInRect (thePoint, &rectControl))
  330.         theValue = CalcValueFromPoint (hControl, thePoint);    // track new point point
  331.     else
  332.         theValue = gStartValue;     // snap to start pos
  333.     
  334.     if (theValue != GetControlValue (hControl))    // if we scrolled
  335.     {
  336.         SetClip (gSaveClip);
  337.  
  338.         gSaveValue = theValue;
  339.         
  340.         MoveScroll (hControl, theValue - GetControlValue (hControl));                                    // move the scroll bar and check edges
  341.         ScrollDrawContent (pWindow, GetControlValue (ghHScrollBar), GetControlValue (ghVScrollBar));    // draw stuff in window
  342.         
  343.         gSaveValue = GetControlValue (hControl);
  344.  
  345.         GetClip (gSaveClip);
  346.         ClipRect (&rectNull);
  347.     }
  348. }
  349.  
  350. // --------------------------------------------------------------------------
  351.  
  352. OSErr BeginThumbTracking (ControlRef hControl)    // start of thumb record values and save clip setting current clip to null
  353. {
  354.     Rect    rectNull = {0, 0, 0, 0};
  355.     OSErr    theErr = noErr;
  356.     Point    thePoint;
  357.     
  358.     gControl = hControl;
  359.     gStartValue = GetControlValue (hControl);
  360.     
  361.     gValueSlop = 0;
  362.     GetMouse (&thePoint);
  363.     gValueSlop = GetControlValue (hControl) - CalcValueFromPoint (hControl, thePoint);    // delta from center
  364.     
  365.     gSaveClip = NewRgn ();
  366.     GetClip (gSaveClip);
  367.     ClipRect (&rectNull);
  368.     
  369.     return theErr;
  370. }
  371.  
  372. // --------------------------------------------------------------------------
  373.  
  374. void DrawOneControlOffscreen (ControlHandle hControl)    // draw a control into our offscreen port
  375. {
  376.     GDHandle hGDSave;
  377.     CGrafPtr pCGrafSave;
  378.     Point ptSave;
  379.     short i = (**hControl).contrlRfCon;
  380.     
  381.     GetGWorld (&pCGrafSave, &hGDSave);
  382.     SetGWorld ((CGrafPtr) gpGWOffScreen, NULL);
  383.     
  384.     if (((gPtCntlPos [i].v) != (**hControl).contrlRect.top) || ((gPtCntlPos [i].h) != (**hControl).contrlRect.left)) 
  385.     {    // reset control pos to original for offscreen update then restore it
  386.         ptSave.v = (**hControl).contrlRect.top;
  387.         ptSave.h = (**hControl).contrlRect.left;            
  388.         MoveControl (hControl, gPtCntlPos [i].h, gPtCntlPos [i].v);
  389.         DrawControlInCurrentPort (hControl); // draw in offscreen
  390.         MoveControl (hControl, ptSave.h, ptSave.v);
  391.     }
  392.     else    // already in correct position
  393.         DrawControlInCurrentPort (hControl); // draw in offscreen
  394.         
  395.     SetGWorld (pCGrafSave, hGDSave);
  396. }
  397. // --------------------------------------------------------------------------
  398.  
  399. void DoContentClick (WindowPtr pWindow, EventRecord * pEvent)
  400. {
  401.     GrafPtr pPortSave = NULL;
  402.     Point pointClick;
  403.     short partWindow = 0;
  404.     ControlHandle hControlHit = NULL;
  405.     ControlActionUPP myActionUPP = NewControlActionProc (ProcScroll);
  406.     ControlActionUPP myThumbUPP = NewControlActionProc (ProcScrollThumbAction);
  407.     
  408.     GetPort (&pPortSave);
  409.     SetPort ((GrafPtr) pWindow);
  410.     
  411.     pointClick = pEvent->where;
  412.     GlobalToLocal (&pointClick);
  413.     
  414.     partWindow = FindControl(pointClick, pWindow, &hControlHit);
  415.     if ((hControlHit == ghHScrollBar) || (hControlHit == ghVScrollBar))
  416.     {
  417.         gStartValue = GetControlValue (hControlHit);    
  418.         switch (partWindow)
  419.         {
  420.             case kControlIndicatorPart:            // live scroll
  421.                 if ( BeginThumbTracking (hControlHit) == noErr )
  422.                 {
  423.                     TrackControl ( hControlHit, pointClick, myThumbUPP);
  424.                     EndThumbTracking ( );
  425.                 }
  426.                 break;
  427.             case kControlUpButtonPart:            // scroll up
  428.             case kControlDownButtonPart:        // scroll down
  429.             case kControlPageUpPart:            // page up
  430.             case kControlPageDownPart:            // page up
  431.                 partWindow = TrackControl (hControlHit, pointClick, myActionUPP);
  432.                 break;
  433.             default:
  434.                 break;
  435.         }
  436.         if (hControlHit)
  437.         {
  438.             if (GetControlValue (hControlHit) - gStartValue) // if we really did move our scroll bar 
  439.                 InvalRect (&pWindow->portRect); // generate a window update
  440.         }
  441.     }
  442.     else if (hControlHit)
  443.     {
  444.         TrackControl(hControlHit, pointClick, (ControlActionUPP) -1);
  445.         DrawOneControlOffscreen (hControlHit);    // update our offscreen info
  446.     }
  447.  
  448.     SetPort ((GrafPtr) pPortSave);
  449. }
  450.  
  451. // --------------------------------------------------------------------------
  452.  
  453. void DoMenu (SInt32 menuResult)
  454. {
  455.     SInt16 theMenu;
  456.     SInt16 theItem;
  457.     Str255 daName;
  458.     MenuRef theMenuHandle;
  459.         
  460.     theMenu = HiWord(menuResult);
  461.     theItem = LoWord(menuResult);
  462.     theMenuHandle = GetMenuHandle(theMenu);
  463.  
  464.     switch (theMenu)
  465.     {
  466.         case kMenuApple:
  467.             switch (theItem)
  468.             {
  469.                 default:
  470.                     OpenDeskAcc(daName);
  471.                     break;
  472.             }
  473.             break;
  474.         case kMenuFile:
  475.             switch (theItem)
  476.             {
  477.                 case kFileQuit:
  478.                     gDone = true;
  479.                     break;
  480.             }
  481.             break;
  482.     }
  483.     HiliteMenu(0);
  484.     DrawMenuBar();
  485. }
  486.  
  487. // --------------------------------------------------------------------------
  488.  
  489. void DoEvent (void)
  490. {
  491.     EventRecord theEvent;
  492.     SInt16 whatPart;
  493.     SInt32 menuResult;
  494.     WindowPtr whichWindow;
  495.     SInt8 theKey;
  496.     SInt8 theCode;
  497.     Rect rectGrow;
  498.     long grow;
  499.     
  500.     if (WaitNextEvent(everyEvent, &theEvent, gSleepTime, NULL))
  501.     {
  502.         switch (theEvent.what)
  503.         {
  504.             case mouseDown:
  505.                 whatPart = FindWindow(theEvent.where, &whichWindow);
  506.                 switch (whatPart)
  507.                 {
  508.                     case inGoAway:
  509.                         break;
  510.                     case inMenuBar:
  511.                         DrawMenuBar();
  512.                         menuResult = MenuSelect(theEvent.where);
  513.                         if (HiWord(menuResult) != 0)
  514.                             DoMenu(menuResult);
  515.                         break;
  516.                     case inSysWindow:
  517.                         SystemClick(&theEvent, whichWindow);
  518.                         break;
  519.                     case inContent:
  520.                         if (whichWindow != FrontWindow ())
  521.                             SelectWindow (whichWindow);
  522.                         else
  523.                             DoContentClick (whichWindow, &theEvent);
  524.                         break;
  525.                     case inDrag:
  526.                         DragWindow (whichWindow, theEvent.where, &(**LMGetGrayRgn()).rgnBBox);
  527.                         break;
  528.                     case inGrow:
  529.                         SetRect (&rectGrow, 100, 100, kOffScreenWidth + kScrollBarWidth, kOffScreenHeight + kScrollBarWidth);
  530.                         grow = GrowWindow (whichWindow, theEvent.where, &rectGrow);
  531.                         if (grow)
  532.                         {
  533.                             SizeWindow (whichWindow, grow & 0x0000FFFF, grow >> 16, true);
  534.                             SetScrollParams (whichWindow);                    // reset scroll limits
  535.                             AdjustScrollBar (gpWindow, ghVScrollBar);        // adjust and draw scroll bars
  536.                             AdjustScrollBar (gpWindow, ghHScrollBar);
  537.                             SetPort (whichWindow);
  538.                             InvalRect (&whichWindow->portRect);                // redraw all
  539.                         }
  540.                         break;
  541.                 }
  542.                 break;
  543.             case keyDown:
  544.             case autoKey:
  545.                 theKey = theEvent.message & charCodeMask;
  546.                 theCode = (theEvent.message & keyCodeMask) >> 8;
  547.                 if ((theEvent.modifiers & cmdKey) != 0)
  548.                 {
  549.                     menuResult = MenuKey(theKey);
  550.                     if (HiWord(menuResult) != 0)
  551.                         DoMenu (menuResult);
  552.                 }
  553.                 break;
  554.             case updateEvt:
  555.                 BeginUpdate((WindowPtr) theEvent.message);
  556.                 DoUpdate((WindowPtr) theEvent.message);
  557.                 EndUpdate((WindowPtr) theEvent.message);
  558.                 break;
  559.             case diskEvt:
  560.                 break;
  561.             case osEvt:
  562.                 break;
  563.  
  564.             case kHighLevelEvent:
  565.                 AEProcessAppleEvent(&theEvent);
  566.                 break;
  567.         }
  568.     }
  569.     else
  570.     {
  571.         // idle tasks
  572.     }
  573. }
  574.  
  575. // --------------------------------------------------------------------------
  576.  
  577. void DrawOffScreen (CGrafPtr pCGOffScreen)
  578. {
  579.     GDHandle hGDSave;
  580.     CGrafPtr pCGrafSave;
  581.     Rect rectSource = (pCGOffScreen->portRect);
  582.     RGBColor rgbGray = {0xC000, 0xC800, 0xD000};
  583.     short i;
  584.     
  585.     GetGWorld (&pCGrafSave, &hGDSave);
  586.     SetGWorld (pCGOffScreen, NULL);
  587.     
  588.     // draw some background
  589.     EraseRect (&rectSource);
  590.     RGBForeColor (&rgbGray);
  591.     PaintRect (&rectSource);    
  592.     MoveTo (rectSource.left, rectSource.top);
  593.     LineTo (rectSource.right, rectSource.bottom);
  594.     MoveTo (rectSource.right, rectSource.top);
  595.     LineTo (rectSource.left, rectSource.bottom);
  596.     
  597.     // draw all my controls
  598.     for (i = 0; i < kNumControls; i++)
  599.         DrawControlInCurrentPort (ghControls[i]); // draw in offscreen (controls should not be scrolled here)
  600.  
  601.     SetGWorld (pCGrafSave, hGDSave);
  602. }
  603.  
  604. // --------------------------------------------------------------------------
  605.  
  606. void SetScrollParams (WindowPtr pWindow)    // set up scroll bars statics
  607. {
  608.     short windowHeight = pWindow->portRect.bottom - pWindow->portRect.top;
  609.     short windowWidth = pWindow->portRect.right - pWindow->portRect.left;
  610.     
  611.     gScrollVThumbSize = windowHeight * (windowHeight - kScrollBarWidthAdjust - kScrollArrowWidth * 2) / kOffScreenHeight; // thumb size based on relative size of window to offscreen
  612.     gScrollHThumbSize = windowWidth * (windowWidth - kScrollBarWidthAdjust - kScrollArrowWidth * 2) / kOffScreenWidth; // thumb size based on relative size of window to offscreen
  613.  
  614.     gTotalVSizeAdjust = ((kScrollArrowWidth * 2) + gScrollVThumbSize);    // amount that scroll bar is less than full height of window
  615.     gTotalHSizeAdjust = ((kScrollArrowWidth * 2) + gScrollHThumbSize);    // amount that scroll bar is less than full height of window
  616. }
  617.  
  618. // --------------------------------------------------------------------------
  619.  
  620. void AdjustScrollBar (WindowPtr pWindow, ControlHandle scrollBar)    // sets up scroll settings and thumb
  621. {
  622.     short totalSize, viewSize;
  623.     short windowHeight = pWindow->portRect.bottom - pWindow->portRect.top;
  624.     short windowWidth = pWindow->portRect.right - pWindow->portRect.left;
  625.     
  626.     // get rect to determine if we are vert or horiz
  627.     if (scrollBar == ghVScrollBar)
  628.     {    // vertical
  629.         totalSize= kOffScreenHeight - (windowHeight - kScrollBarWidthAdjust); // total doc. height - visable doc
  630.         viewSize= windowHeight + kScrollBarWidth; // vis. doc. height
  631.         MoveControl (scrollBar, windowWidth - kScrollBarWidthAdjust, -1);
  632.         SizeControl (scrollBar, kScrollBarWidth, windowHeight + 2 - kScrollBarWidthAdjust);
  633.     }
  634.     else
  635.     {    // horizontal
  636.         totalSize= kOffScreenWidth - (windowWidth - kScrollBarWidthAdjust); // total doc. width - visable doc
  637.         viewSize= windowWidth + kScrollBarWidth; // vis. doc. width
  638.         MoveControl (scrollBar, -1, windowHeight - kScrollBarWidthAdjust);
  639.         SizeControl (scrollBar, windowWidth + 2 - kScrollBarWidthAdjust, kScrollBarWidth);
  640.     }
  641.     // set the min, max, and current value of the scroll bar
  642.     SetControl32BitMinimum (scrollBar, 0);
  643.     SetControl32BitMaximum (scrollBar, totalSize);
  644.     SetControl32BitValue (scrollBar, GetControlValue (scrollBar));
  645.     // set the scroll bar view size to create a proportional scroll box
  646.     SetControlViewSize (scrollBar, viewSize);
  647. }
  648.  
  649. // --------------------------------------------------------------------------
  650.  
  651. void InitToolbox(void)    // standard inits
  652. {
  653.     MenuHandle menu;
  654.     SInt16 modifiers = 0;
  655.     EventRecord event;
  656.  
  657.     MaxApplZone ();
  658.  
  659.     InitGraf((Ptr) &qd.thePort);
  660.     InitFonts();
  661.     InitWindows();
  662.     InitMenus();
  663.     TEInit();
  664.     InitDialogs(nil);
  665.     InitCursor();
  666.     
  667.     qd.randSeed =  TickCount();
  668.  
  669.     // init events
  670.     EventAvail(everyEvent, &event);
  671.     modifiers |= event.modifiers;
  672.     EventAvail(everyEvent, &event);
  673.     modifiers |= event.modifiers;
  674.     EventAvail(everyEvent, &event);
  675.     modifiers |= event.modifiers;
  676.  
  677.     // Init Menus
  678.     menu = NewMenu (kMenuApple, "\p\024");            // new  apple menu
  679.     InsertMenu (menu, 0);                            // add menu to end
  680.     AppendResMenu(menu, 'DRVR');
  681.     
  682.     menu = NewMenu (kMenuFile, "\pFile");            // new menu
  683.     InsertMenu (menu, 0);                            // add menu to end
  684.     AppendMenu (menu, "\pQuit/Q");                     // add items
  685.     
  686.     DrawMenuBar();
  687.  
  688. // --------------------------------------------------------------------------
  689.  
  690. Boolean SetUp (void) // set up windows, controls, off screen
  691. {
  692.     short i;
  693.     MenuHandle hMenu;
  694.     Rect rectSize;
  695.  
  696.     InitToolbox ();
  697.  
  698.     SetRect (&gRectWindowGbl, 0, 0, kWindowWidth, kWindowHeight);
  699.     OffsetRect (&gRectWindowGbl, kWindowOffset, kWindowOffset);
  700.     gpWindow = NewCWindow (NULL, &gRectWindowGbl, "\pControl Scroll Test", false, kWindowGrowDocumentProc, (WindowPtr) -1, false, 0);
  701.     SetScrollParams (gpWindow);
  702.     
  703.     SetRect (&rectSize, -1, kWindowHeight - kScrollBarWidthAdjust, kWindowWidth + 1 - kScrollBarWidthAdjust, kWindowHeight + 1);
  704.     ghHScrollBar = NewControl (gpWindow, &rectSize, "\p", false, 0, 0, 0, kControlScrollBarProc, 0);
  705.     if (!ghHScrollBar)
  706.         return false;
  707.     AdjustScrollBar (gpWindow, ghHScrollBar);
  708.     ShowControl (ghHScrollBar);
  709.     
  710.     SetRect (&rectSize, kWindowWidth - kScrollBarWidthAdjust, -1, kWindowWidth + 1, kWindowHeight + 1 - kScrollBarWidthAdjust);
  711.     ghVScrollBar = NewControl (gpWindow, &rectSize, "\p", false, 0, 0, 0, kControlScrollBarProc, 0);
  712.     if (!ghVScrollBar)
  713.         return false;
  714.     AdjustScrollBar (gpWindow, ghVScrollBar);
  715.     ShowControl (ghVScrollBar);
  716.  
  717.     hMenu = NewMenu (kButtonMenuID, "\pButton");            // new menu
  718.     AppendMenu (hMenu, "\pItem 1;Item 2;Item 3;Item 4");     // add items
  719.     InsertMenu (hMenu, hierMenu);                            // add menu to end
  720.  
  721.     for (i = 0; i < kNumControls; i++)
  722.     {
  723.         short top = 10 + (abs (Random ()) % (kOffScreenHeight - kScrollBarWidth - 10 - 20));
  724.         short left = 10 + (abs (Random ()) % (kOffScreenWidth - kScrollBarWidth - 10 - 75));
  725.         SetRect (&rectSize, left, top, left + 75,  top + 20); 
  726.         // NOTE: intial pos is stored in gPtCntlPos array to allow reference during scrolling
  727.         ghControls [i] = NewControl (gpWindow, &rectSize, "\p", true, 0, kButtonMenuID, 0, popupMenuProc, i);
  728.         if (!(ghControls [i]))
  729.             return false;
  730.         gPtCntlPos [i].v = rectSize.top;
  731.         gPtCntlPos [i].h = rectSize.left;
  732.     }
  733.     
  734.     SetRect (&rectSize, 0, 0, kOffScreenWidth, kOffScreenHeight);
  735.     if (NewGWorld (&gpGWOffScreen, 32, &rectSize, NULL, NULL, 0) != noErr)
  736.         return false;
  737.         
  738.     DrawOffScreen ((CGrafPtr) gpGWOffScreen);
  739.     ShowWindow (gpWindow);
  740.     return true;
  741. }
  742.  
  743. // functions (external/public) ----------------------- ----------------------
  744.  
  745. int main (void)
  746. {    
  747.     if (SetUp ())
  748.         while (!gDone) 
  749.             DoEvent ();
  750.     CleanUp ();
  751.     return 0;
  752. }